/*
 * Copyright 2024 ywcai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

`include "../core/defines.v"
`include "axi_defines.v"
`timescale 1ns/1ps

module axi_bus_bridge(
	input	wire						clk,
	input	wire						rst_n,

	input	wire						m0_req_i,
	input	wire						m0_we_i,
    input	wire[`MemAddrBus]			m0_addr_i,
    input	wire[`AxiDataBus]			m0_wr_data_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m0_strb_i,
	input	wire[11:0]					m0_pulse_bits_i,
	input	wire						m0_m_bus_grant_i,
	input	wire						m0_io_bus_grant_i,

	input	wire						m1_req_i,
	input	wire						m1_we_i,
    input	wire[`MemAddrBus]			m1_addr_i,
    input	wire[`AxiDataBus]			m1_wr_data_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m1_strb_i,
	input	wire[11:0]					m1_pulse_bits_i,
	input	wire						m1_m_bus_grant_i,
	input	wire						m1_io_bus_grant_i,

	input	wire						m2_req_i,
	input	wire						m2_we_i,
    input	wire[`MemAddrBus]			m2_addr_i,
    input	wire[`AxiDataBus]			m2_wr_data_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m2_strb_i,
	input	wire[11:0]					m2_pulse_bits_i,
	input	wire						m2_m_bus_grant_i,
	input	wire						m2_io_bus_grant_i,

	input	wire						m3_req_i,
	input	wire						m3_we_i,
    input	wire[`MemAddrBus]			m3_addr_i,
    input	wire[`AxiDataBus]			m3_wr_data_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m3_strb_i,
	input	wire[11:0]					m3_pulse_bits_i,
	input	wire						m3_m_bus_grant_i,
	input	wire						m3_io_bus_grant_i,

	input	wire[`RegDataBus]			s0_rd_data_i,
	input	wire[1:0]					s0_errcode_i,
	input	wire[`RegDataBus]			s1_rd_data_i,
	input	wire[1:0]					s1_errcode_i,
	input	wire[`RegDataBus]			s2_rd_data_i,
	input	wire[1:0]					s2_errcode_i,
	input	wire[`RegDataBus]			s3_rd_data_i,
	input	wire[1:0]					s3_errcode_i,
	input	wire[`RegDataBus]			s4_rd_data_i,
	input	wire[1:0]					s4_errcode_i,
	input	wire[`RegDataBus]			s5_rd_data_i,
	input	wire[1:0]					s5_errcode_i,
	input	wire[`RegDataBus]			s6_rd_data_i,
	input	wire[1:0]					s6_errcode_i,
	input	wire[`RegDataBus]			s7_rd_data_i,
	input	wire[1:0]					s7_errcode_i,

	output	wire[`AxiDataBus]			m0_rd_data_o,
	output	wire[1:0]					m0_errcode_o,

	output	wire[`AxiDataBus]			m1_rd_data_o,
	output	wire[1:0]					m1_errcode_o,

	output	wire[`AxiDataBus]			m2_rd_data_o,
	output	wire[1:0]					m2_errcode_o,

	output	wire[`AxiDataBus]			m3_rd_data_o,
	output	wire[1:0]					m3_errcode_o,

    output  wire               			s0_we_o,
	output	wire[`MemAddrBus]			s0_addr_o,
	output	wire[`RegDataBus]			s0_wr_data_o,
	output	wire[7:0]					s0_strb_o,

    output  wire                		s1_we_o,
	output	wire[`MemAddrBus]			s1_addr_o,
	output	wire[`RegDataBus]			s1_wr_data_o,
	output	wire[7:0]					s1_strb_o,

    output  wire                		s2_we_o,
	output	wire[`MemAddrBus]			s2_addr_o,
	output	wire[`RegDataBus]			s2_wr_data_o,
	output	wire[7:0]					s2_strb_o,

    output  wire                		s3_we_o,
	output	wire[`MemAddrBus]			s3_addr_o,
	output	wire[`RegDataBus]			s3_wr_data_o,
	output	wire[7:0]					s3_strb_o,

    output  wire                		s4_we_o,
	output	wire[`MemAddrBus]			s4_addr_o,
	output	wire[`RegDataBus]			s4_wr_data_o,
	output	wire[7:0]					s4_strb_o,

    output  wire                		s5_we_o,
	output	wire[`MemAddrBus]			s5_addr_o,
	output	wire[`RegDataBus]			s5_wr_data_o,
	output	wire[7:0]					s5_strb_o,

    output  wire                		s6_we_o,
	output	wire[`MemAddrBus]			s6_addr_o,
	output	wire[`RegDataBus]			s6_wr_data_o,
	output	wire[7:0]					s6_strb_o,

    output  wire                		s7_we_o,
	output	wire[`MemAddrBus]			s7_addr_o,
	output	wire[`RegDataBus]			s7_wr_data_o,
	output	wire[7:0]					s7_strb_o,

	output	wire						transact_done_o
	);

	wire						awValid;
	wire						awReady;
	wire[`MemAddrBus]			awAddr;
	wire[7:0]					awId;
	wire[7:0]					awLen;
	wire[2:0]					awSize;
	wire[1:0]					awBurst;
	wire						awLock;
	wire[3:0]					awCache;
	wire[2:0]					awProt;
	wire[`RegDataBus]			wData;
	wire[7:0]					wStrb;
	wire						wLast;
	wire						wValid;
	wire						wReady;
	wire[1:0]					bResp;
	wire[7:0]					bId;
	wire						bComp;
	wire						bValid;
	wire						bReady;
	wire						arValid;
	wire[`MemAddrBus]			arAddr;
	wire[7:0]					arId;
	wire[7:0]					arLen;
	wire[2:0]					arSize;
	wire[1:0]					arBurst;
	wire						arLock;
	wire[3:0]					arCache;
	wire[2:0]					arProt;
	wire						arReady;
	wire[`RegDataBus]			rData;
	wire[1:0]					rResp;
	wire[7:0]					rId;
	wire						rLast;
	wire						rValid;
	wire						rReady;

	wire						m_we;
    wire[`MemAddrBus]			m_addr;
	wire[`AXI_DATA_BITS/8-1:0]	m_strb;
    wire[`AxiDataBus]			m_wr_data;
	wire[`AxiDataBus]			m_rd_data_i;
	wire[11:0]					m_pulse_bits;
	wire[1:0]					m_errcode_i;
	wire						s_we_o;
	wire[`MemAddrBus]			s_addr_o;
	wire[`RegDataBus]			s_wr_data_o;
	wire[7:0]					s_strb_o;
	wire[`RegDataBus]			s_rd_data_i;
    wire[1:0]           		s_errcode_i;
	wire						master_req;
	wire						m0_grant;
	wire						m1_grant;
	wire						m2_grant;
	wire						m3_grant;
	wire						s0_sel;
	wire						s1_sel;
	wire						s2_sel;
	wire						s3_sel;
	wire						s4_sel;
	wire						s5_sel;
	wire						s6_sel;
	wire						s7_sel;

	assign master_req = (m0_req_i & (m0_m_bus_grant_i | m0_io_bus_grant_i))
		| (m1_req_i & (m1_m_bus_grant_i | m1_io_bus_grant_i))
		| (m2_req_i & (m2_m_bus_grant_i | m2_io_bus_grant_i))
		| (m3_req_i & (m3_m_bus_grant_i | m3_io_bus_grant_i));

	axi_master_mux i_master_mux(
		.m_rd_data_i(m_rd_data_i),
		.m_errcode_i(m_errcode_i),
		.m0_we_i(m0_we_i),
		.m0_addr_i(m0_addr_i),
		.m0_wr_data_i(m0_wr_data_i),
		.m0_pulse_bits_i(m0_pulse_bits_i),
		.m0_strb_i(m0_strb_i),
		.m0_m_bus_grant_i(m0_m_bus_grant_i),
		.m0_io_bus_grant_i(m0_io_bus_grant_i),
		.m1_we_i(m1_we_i),
		.m1_addr_i(m1_addr_i),
		.m1_wr_data_i(m1_wr_data_i),
		.m1_pulse_bits_i(m1_pulse_bits_i),
		.m1_strb_i(m1_strb_i),
		.m1_m_bus_grant_i(m1_m_bus_grant_i),
		.m1_io_bus_grant_i(m1_io_bus_grant_i),
		.m2_we_i(m2_we_i),
		.m2_addr_i(m2_addr_i),
		.m2_wr_data_i(m2_wr_data_i),
		.m2_pulse_bits_i(m1_pulse_bits_i),
		.m2_strb_i(m2_strb_i),
		.m2_m_bus_grant_i(m2_m_bus_grant_i),
		.m2_io_bus_grant_i(m2_io_bus_grant_i),
		.m3_we_i(m3_we_i),
		.m3_addr_i(m3_addr_i),
		.m3_wr_data_i(m3_wr_data_i),
		.m3_pulse_bits_i(m3_pulse_bits_i),
		.m3_strb_i(m3_strb_i),
		.m3_m_bus_grant_i(m3_m_bus_grant_i),
		.m3_io_bus_grant_i(m3_io_bus_grant_i),
		.m_we_o(m_we),
		.m_addr_o(m_addr),
		.m_strb_o(m_strb),
		.m_wr_data_o(m_wr_data),
		.m_pulse_bits_o(m_pulse_bits),
		.m0_rd_data_o(m0_rd_data_o),
		.m0_errcode_o(m0_errcode_o),
		.m1_rd_data_o(m1_rd_data_o),
		.m1_errcode_o(m1_errcode_o),
		.m2_rd_data_o(m2_rd_data_o),
		.m2_errcode_o(m2_errcode_o),
		.m3_rd_data_o(m3_rd_data_o),
		.m3_errcode_o(m3_errcode_o)
	);

	axi_master i_axi_master(
		.clk(clk),
		.rst_n(rst_n),
		.m_req_i(master_req),
		.m_we_i(m_we),
		.m_addr_i(m_addr),
		.m_wr_data_i(m_wr_data),
		.m_pulse_bits_i(m_pulse_bits),
		.m_strb_i(m_strb),
		.m_axi_awReady(awReady),
		.m_axi_wReady(wReady),
		.m_axi_bValid(bValid),
		.m_axi_bResp(bResp),
		.m_axi_bId(bId),
		.m_axi_bComp(bComp),
		.m_axi_arReady(arReady),
		.m_axi_rValid(rValid),
		.m_axi_rResp(rResp),
		.m_axi_rId(rId),
		.m_axi_rLast(rLast),
		.m_axi_rData(rData),
		.m_axi_awValid(awValid),
		.m_axi_awAddr(awAddr),
		.m_axi_awId(awId),
		.m_axi_awLen(awLen),
		.m_axi_awSize(awSize),
		.m_axi_awBurst(awBurst),
		.m_axi_awLock(awLock),
		.m_axi_awCache(awCache),
		.m_axi_awProt(awProt),
		.m_axi_wData(wData),
		.m_axi_wStrb(wStrb),
		.m_axi_wLast(wLast),
		.m_axi_wValid(wValid),
		.m_axi_bReady(bReady),
		.m_axi_arValid(arValid),
		.m_axi_arAddr(arAddr),
		.m_axi_arId(arId),
		.m_axi_arLen(arLen),
		.m_axi_arSize(arSize),
		.m_axi_arBurst(arBurst),
		.m_axi_arLock(arLock),
		.m_axi_arCache(arCache),
		.m_axi_arProt(arProt),
		.m_axi_rReady(rReady),
		.m_rd_data_o(m_rd_data_i),
		.errcode(m_errcode_i),
		.transact_done_o(transact_done_o)
	);

	axi_slave i_axi_slave(
		.clk(clk),
		.rst_n(rst_n),
		.s_rd_data_i(s_rd_data_i),
		.s_errcode_i(s_errcode_i),
		.s_axi_awValid(awValid),
		.s_axi_awAddr(awAddr),
		.s_axi_awId(awId),
		.s_axi_awLen(awLen),
		.s_axi_awSize(awSize),
		.s_axi_awBurst(awBurst),
		.s_axi_awLock(awLock),
		.s_axi_awCache(awCache),
		.s_axi_awProt(awProt),
		.s_axi_wData(wData), 
		.s_axi_wStrb(wStrb),
		.s_axi_wLast(wLast),
		.s_axi_wValid(wValid),
		.s_axi_awReady(awReady),
		.s_axi_wReady(wReady),
		.s_axi_bResp(bResp),
		.s_axi_bId(bId),
		.s_axi_bComp(bComp),
		.s_axi_bValid(bValid),
		.s_axi_bReady(bReady),
		.s_axi_arValid(arValid),
		.s_axi_arAddr(arAddr),
		.s_axi_arId(arId),
		.s_axi_arLen(arLen),
		.s_axi_arSize(arSize),
		.s_axi_arBurst(arBurst),
		.s_axi_arLock(arLock),
		.s_axi_arCache(arCache),
		.s_axi_arProt(arProt),
		.s_axi_arReady(arReady),
		.s_axi_rData(rData),
		.s_axi_rResp(rResp),
		.s_axi_rId(rId),
		.s_axi_rLast(rLast),
		.s_axi_rValid(rValid),
		.s_axi_rReady(rReady),
		.s_we_o(s_we_o),
		.s_addr_o(s_addr_o),
		.s_wr_data_o(s_wr_data_o),
		.s_strb_o(s_strb_o)
	);

	axi_addr_dec i_addr_dec(
		.req_addr_i(s_addr_o),
		.s0_sel_o(s0_sel),
		.s1_sel_o(s1_sel),
		.s2_sel_o(s2_sel),
		.s3_sel_o(s3_sel),
		.s4_sel_o(s4_sel),
		.s5_sel_o(s5_sel),
		.s6_sel_o(s6_sel),
		.s7_sel_o(s7_sel)
	);

	axi_slave_mux i_slave_mux(
		.s_we_i(s_we_o),
		.s_addr_i(s_addr_o),
		.s_wr_data_i(s_wr_data_o),
		.s_strb_i(s_strb_o),
		.s0_sel_i(s0_sel),
		.s1_sel_i(s1_sel),
		.s2_sel_i(s2_sel),
		.s3_sel_i(s3_sel),
		.s4_sel_i(s4_sel),
		.s5_sel_i(s5_sel),
		.s6_sel_i(s6_sel),
		.s7_sel_i(s7_sel),
		.s0_rd_data_i(s0_rd_data_i),
		.s0_errcode_i(s0_errcode_i),
		.s1_rd_data_i(s1_rd_data_i),
		.s1_errcode_i(s1_errcode_i),
		.s2_rd_data_i(s2_rd_data_i),
		.s2_errcode_i(s2_errcode_i),
		.s3_rd_data_i(s3_rd_data_i),
		.s3_errcode_i(s3_errcode_i),
		.s4_rd_data_i(s4_rd_data_i),
		.s4_errcode_i(s4_errcode_i),
		.s5_rd_data_i(s5_rd_data_i),
		.s5_errcode_i(s5_errcode_i),
		.s6_rd_data_i(s6_rd_data_i),
		.s6_errcode_i(s6_errcode_i),
		.s7_rd_data_i(s7_rd_data_i),
		.s7_errcode_i(s7_errcode_i),
        .s0_we_o(s0_we_o),
		.s0_addr_o(s0_addr_o),
		.s0_wr_data_o(s0_wr_data_o),
		.s0_strb_o(s0_strb_o),
        .s1_we_o(s1_we_o),
		.s1_addr_o(s1_addr_o),
		.s1_wr_data_o(s1_wr_data_o),
		.s1_strb_o(s1_strb_o),
        .s2_we_o(s2_we_o),
		.s2_addr_o(s2_addr_o),
		.s2_wr_data_o(s2_wr_data_o),
		.s2_strb_o(s2_strb_o),
        .s3_we_o(s3_we_o),
		.s3_addr_o(s3_addr_o),
		.s3_wr_data_o(s3_wr_data_o),
		.s3_strb_o(s3_strb_o),
        .s4_we_o(s4_we_o),
		.s4_addr_o(s4_addr_o),
		.s4_wr_data_o(s4_wr_data_o),
		.s4_strb_o(s4_strb_o),
        .s5_we_o(s5_we_o),
		.s5_addr_o(s5_addr_o),
		.s5_wr_data_o(s5_wr_data_o),
		.s5_strb_o(s5_strb_o),
        .s6_we_o(s6_we_o),
		.s6_addr_o(s6_addr_o),
		.s6_wr_data_o(s6_wr_data_o),
		.s6_strb_o(s6_strb_o),
        .s7_we_o(s7_we_o),
		.s7_addr_o(s7_addr_o),
		.s7_wr_data_o(s7_wr_data_o),
		.s7_strb_o(s7_strb_o),
		.s_rd_data_o(s_rd_data_i),
		.s_errcode_o(s_errcode_i)
	);

endmodule
